#include "actor.hpp"
#include "ActorManager.hpp"
#include "DrawEvent.hpp"
#include "Engine.hpp"

namespace wolf {

void Actor::initialize()
    {
    }

    void Actor::_init(int x_, int y_) {
	velX = velY = 0;
	x = x_;
	y = y_;
	previousX = previousY = 0;
	pixelCollision = false;
	ActorManager::getInstance().addActor(*this);
	drawHandler = NULL;
}

Actor::Actor(const Sprite &sprite_, int x_, int y_, int depth) :
		Layer(depth), sprite(sprite_) {
	_init(x_, y_);
}

Actor::Actor(const string & file, Uint16 nCollumns, Uint16 nRows, int x_,
		int y_, int depth) :
		Layer(depth), sprite(file.c_str(), nCollumns, nRows) {
	_init(x_, y_);
}

Actor::Actor(SDL_Surface *src, Uint16 nCollumns, Uint16 nRows, int x_, int y_,
		int depth) :
		Layer(depth), sprite(src, nCollumns, nRows) {
	_init(x_, y_);
}

Actor::Actor(SDL_RWops *src, Uint16 nCollumns, Uint16 nRows, int x_, int y_,
		int depth) :
		Layer(depth), sprite(src, nCollumns, nRows, false) {
	_init(x_, y_);
}

Actor::~Actor(void) {
	ActorManager::getInstance().removeActor(*this);
}

void Actor::draw(SDL_Surface *dst) {
	if (drawHandler) {
		DrawEvent drawEvent(Engine::getInstance(), *this, dst);
		(this->*drawHandler)(drawEvent);
	} else
		drawSprite(dst);
}

void Actor::drawSprite(SDL_Surface *dst) {
	sprite.draw(dst, x, y);
}

void Actor::drawSprite(SDL_Surface *dst, int x, int y) {
	sprite.draw(dst, x, y);
}

void Actor::doFrame(void) {
	previousX = x;
	previousY = y;
	x += velX;
	y += velY;
}

// Collision related
bool Actor::collides(const Actor &other) const {
	Rect sRect(x, y, sprite.getWidth(), sprite.getHeight());
	Rect oRect(other.x, other.y, other.sprite.getWidth(),
			other.sprite.getHeight());
	Rect iRect(sRect.intersection(oRect));
	if (!iRect.empty()) {
		return true;
	}
	return false;
}

void Actor::goLastPosition(void) {
	x = previousX;
	y = previousY;
}

int Actor::getPreviousX() const {
	return previousX;
}

int Actor::getPreviousY() const {
	return previousY;
}

const Sprite &Actor::getSprite() const {
	return sprite;
}

Sprite &Actor::getSprite() {
	return sprite;
}

int Actor::getVelX() const {
	return velX;
}

int Actor::getVelY() const {
	return velY;
}

int Actor::getX() const {
	return x;
}

int Actor::getY() const {
	return y;
}

void Actor::setSprite(const Sprite &sprite) {
	this->sprite = sprite;
}

void Actor::setVelX(int velX) {
	this->velX = velX;
}

void Actor::setVelY(int velY) {
	this->velY = velY;
}

void Actor::setX(int x) {
	this->x = x;
}

void Actor::setY(int y) {
	this->y = y;
}

void Actor::connectFrameEvent(mpFrameHandler handler) {
	ActorManager::getInstance().connectFrame(*this, handler);
}

//void Actor::disconnectFrameEvent() {
//	ActorManager::getInstance().disconnectFrame(*this);
//}

void Actor::connectStartFrameEvent(mpFrameHandler handler) {
	ActorManager::getInstance().connectStartFrame(*this, handler);
}

//void Actor::disconnectStartFrameEvent() {
//	ActorManager::getInstance().disconnectStartFrame(*this);
//}

void Actor::connectEndFrameEvent(mpFrameHandler handler) {
	ActorManager::getInstance().connectEndFrame(*this, handler);
}

//void Actor::disconnectEndFrameEvent() {
//	ActorManager::getInstance().disconnectEndFrame(*this);
//}

void Actor::connectDrawEvent(mpDrawHandler handler) {
	drawHandler = handler;
}

//void Actor::disconnectDrawEvent() {
//	drawHandler = NULL;
//}

void Actor::connectCollisionEvent(mpCollisionHandler handler) {
	ActorManager::getInstance().connectCollision(*this, handler);
}

//void Actor::disconnectCollisionDrawEvent() {
//	ActorManager::getInstance().disconnectCollision(*this);
//}

}
